/*******************************************************************************

  Pilot Intelligence Library
    http://www.pilotintelligence.com/

  ----------------------------------------------------------------------------

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.

*******************************************************************************/

#include <Poco/Net/NetworkInterface.h>
#include <Poco/Process.h>
#include <Poco/PipeStream.h>

#include <base/regexp/RegularExpression.h>
#include <base/utils/utils.h>

#include "Network_Utils.h"


namespace pi {

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

inline void setSocketAdress(RSocketAddress &sa, const Poco::Net::IPAddress &ip)
{
    sa.address = ip.toString();
    sa.port = -1;
}




////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

NetworkInterface::NetworkInterface()
{
    m_name              = "";
    m_displayName       = "";
    m_supportsIPv4      = 1;
    m_supportsIPv6      = 1;
}

NetworkInterface::~NetworkInterface()
{

}


NetworkInterface::NetworkInterfaceList NetworkInterface::list()
{
    Poco::Net::NetworkInterface::NetworkInterfaceList l;
    NetworkInterfaceList lNew;

    l = Poco::Net::NetworkInterface::list();

    for(int i=0; i<l.size(); i++) {
        Poco::Net::NetworkInterface &nic = l[i];

        NetworkInterface nNew;
        nNew.m_name             = nic.name();
        nNew.m_displayName      = nic.displayName();

        setSocketAdress(nNew.m_address,             nic.address());
        setSocketAdress(nNew.m_subnetAddress,       nic.subnetMask());
        setSocketAdress(nNew.m_broadcastAddress,    nic.broadcastAddress());

        nNew.m_macAddress       = nic.macAddress();

        nNew.m_supportsIPv4     = nic.supportsIPv4();
        nNew.m_supportsIPv6     = nic.supportsIPv6();

        lNew.push_back(nNew);
    }

    return lNew;
}


int NetworkInterface::listMACs(std::vector<MACAddress>& macAddress)
{
    std::string res;
    char buffer[2048];
    int nBuf = 2047;

    macAddress.clear();

    // call system utils to get all configurations
    {
        std::string cmd;
        std::vector<std::string> args;

    #ifdef PIL_LINUX
        cmd = "ifconfig";
    #endif

    #if defined(PIL_WINDOWS) || defined(PIL_MINGW)
        cmd = "ipconfig";
        args.push_back("/all");
    #endif

        Poco::Pipe outPipe;
        Poco::ProcessHandle ph = Poco::Process::launch(cmd, args,
                                                       0, &outPipe, 0);
        ph.wait();

        while(1) {
            int n = outPipe.readBytes(buffer, nBuf);
            if( n == 0 ) break;

            buffer[n] = 0;
            res = res + buffer;
        }
    }

    // parse MAC address
    {
        RegularExpression re_mac("([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}");
        RegularExpression re_macFake("([0-9a-fA-F]{2}[:-]){6}[0-9a-fA-F]{2}");

        RegularExpression::Match m;
        int r;

        StringArray sa;
        sa = split_line(res);

        for(int i=0; i<sa.size(); i++) {
            std::string& s = sa[i];

            // determin fake MAC address
            r = re_macFake.match(s, 0, m);
            if( m.offset != std::string::npos && m.length > 0 ) continue;

            // find real MAC address
            r = re_mac.match(s, 0, m);
            if( m.offset != std::string::npos && m.length > 0 ) {
                memcpy(buffer, s.c_str() + m.offset, m.length);
                buffer[m.length] = 0;

                MACAddress mac;
                mac.fromString(buffer);
                macAddress.push_back(mac);
            }
        }
    }

    return 0;
}


} // end of namespace pi

